# 2.X 定义类的方式
# class Player:
# 3.X 定义类的方式


class Player(object):
    # 静态成员，供实例方法、类方法和静态方法调用
    hobby = 'playing'
    count = 0

    # python中没有访问权限控制的机制，全靠自觉
    # 三种方法，实例方法，第一个参数必须是self；类方法，必须至少携带个cls的类参数；静态方法
    # 定义构造函数，第一个参数一定是self
    def __init__(self, name, hp, occ):
        # python允许在定义class的时候，定义一个特殊的__slots__变量，来限制该class实例能添加的属性，但是似乎不起作用
        # __slots__ = ('name', '_hp', '__occ')
        self.__slots__ = ('name', '_hp', '__occ')
        # 定义公有属性，外部可直接访问
        self.name = name
        # 外部可直接访问
        self._hp = hp
        # 可以这样调用，但不建议
        Player.hobby = 'swimming'
        # 定义私有属性，所谓的私有，只是编译器改名字而已，如改为 _Player__occ，外部依然可以访问
        self.__occ = occ
        self.count_increase()

    # 第一个参数一定是self，打印信息，python中可直接调用__dict__来获取
    def print_role(self):
        print('original method: name = %s, hp = %s, occ = %s' % (self.name, self._hp, self.__occ))

    # 定义函数，修改公有属性
    def update_name(self, name):
        self.name = name

    # 定义函数，修改公有属性
    def update_hp(self, hp):
        self._hp = hp

    # 定义函数，修改私有属性
    def update_occ(self, occ):
        self.__occ = occ

    # 定义类方法，类方法是给类用的，类在使用时会将类本身当做参数传给类方法的第一个参数
    @classmethod
    def get_hobby(cls):
        print('class method: hobby = %s' % cls.hobby)
        return cls.hobby

    # 定义类方法
    @classmethod
    def update_hobby(cls, hobby):
        cls.hobby = hobby

    # 定义静态方法
    @staticmethod
    def count_increase():
        Player.count += 1
        print('static method: count = %s' % Player.count)

    # 将方法定义的像属性那样调用
    @property
    def get_name(self):
        print('property method: current name = %s' % self.name)
        return self.name

    # 将方法定义的像属性那样调用
    @property
    def get_hp(self):
        return self._hp

    # 将方法定义的像属性那样调用
    @property
    def get_occ(self):
        return self.__occ

    # 重写str，类似于java的tostring
    def __str__(self):
        return "name:{}, hp:{}, occupation:{}".format(self.name, self._hp, self.__occ)

    # 定义析构函数
    def __del__(self):
        pass


# 定义一个实例
player = Player('tom', 100, 'warrior')
# player.print_role()
print(player)                   # name:tom, hp:100, occupation:warrior
# 打印成员属性和方法名
print(dir(player))
# 打印构造函数里面的属性
print(player.__dict__)
# player = Player('jerry', 99, 'master')
player.name = 'jerry'
player._hp = 99                 # 可以直接访问，且有效

player.__occ__ = 'master'       # 1 外部依然可以访问，但是只能改变__dict__里面__occ__的属性，实际打印出来没有改变
print(player.__dict__)          # {'__slots__': ('name', '_hp', '__occ'), '__occ__': 'master', '_Player__occ': 'warrior', '_hp': 99, 'name': 'jerry'}
player.print_role()             # original method: name = jerry, hp = 99, occ = warrior

player.update_occ('wcc')        # 2 这种方式更改的是_Player__occ属性，实际打印出来有改变
print(player.__dict__)          # {'__slots__': ('name', '_hp', '__occ'), '__occ__': 'master', '_Player__occ': 'wcc', '_hp': 99, 'name': 'jerry'}
player.print_role()             # original method: name = jerry, hp = 99, occ = wcc

player._Player__occ = 'general'  # 3 这种方式更改的是_Player__occ属性，实际打印出来有改变
print(player.__dict__)          # {'__slots__': ('name', '_hp', '__occ'), '__occ__': 'master', '_Player__occ': 'general', '_hp': 99, 'name': 'jerry'}
player.print_role()             # original method: name = jerry, hp = 99, occ = general

# 调用类方法
player.update_hobby("badminton")
# 调用类方法
player.get_hobby()
# 调用静态方法
player.count_increase()
# 调用property修饰的方法
player.get_name
player.get_hp
player.get_occ


